#pragma once
#include <memory>
#include <sw/redis++/redis.h>
#include <sw/redis++/connection.h>

namespace shared {

namespace dal {

using RedisPtr = std::shared_ptr<sw::redis::Redis>;

class RedisClientFactory
{
public:
    static RedisPtr create(const std::string& host, uint16_t port, int db, bool keepAlive)
    {
        sw::redis::ConnectionOptions opts;
        opts.host = host;
        opts.port = port;
        opts.db = db;
        opts.keep_alive = keepAlive;
        return std::make_shared<sw::redis::Redis>(opts);
    }
};

class Session
{
public:
    Session(const RedisPtr& redisClient) : redisClient_(redisClient) {}
    
    bool append(const std::string& sessionId, const std::string& userId) 
    { 
        return redisClient_->set(sessionId, userId);
    }
    void remove(const std::string& sessionId)
    {
        redisClient_->del(sessionId);
    }
    sw::redis::OptionalString getUserId(const std::string& sessionId)
    {
        return redisClient_->get(sessionId);
    }
private:
    RedisPtr redisClient_;
};

class Status
{
public:
    Status(const RedisPtr& redisClient) : redisClient_(redisClient) {}

    bool append(const std::string& userId)
    {
        return redisClient_->set(userId, "");
    }
    void remove(const std::string& userId)
    {
        redisClient_->del(userId);
    }
    bool exists(const std::string& userId)
    {
        return static_cast<bool>(redisClient_->get(userId));
    }
private:
    RedisPtr redisClient_;
};

class VerifyCode
{
public:
    VerifyCode(const RedisPtr& redisClient) : redisClient_(redisClient) {}

    bool append(const std::string& verifyCodeId, const std::string& code,
        const std::chrono::milliseconds& ttl = std::chrono::milliseconds(60000))
    {
        return redisClient_->set(verifyCodeId, code, ttl);
    }
    void remove(const std::string& verifyCodeId)
    {
        redisClient_->del(verifyCodeId);
    }
    sw::redis::OptionalString getVerifyCode(const std::string& verifyCodeId)
    {
        return redisClient_->get(verifyCodeId);
    }
private:
    RedisPtr redisClient_;  
};

using SessionPtr = std::shared_ptr<Session>;
using StatusPtr = std::shared_ptr<Status>;
using VerifyCodePtr = std::shared_ptr<VerifyCode>;

}}